package net;

import data.user.User;
import java.io.Closeable;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.Observable;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author 4n
 */
public abstract class Connection extends Observable implements Closeable {

    protected final Socket socket;

    protected User user;

    protected PacketBuffer pb;

    public Connection(Socket socket) throws IOException {
        this.socket = socket;

        user = new User();

        pb = new PacketBuffer(socket.getInputStream());
    }

    public abstract void start() throws IOException;

    protected synchronized void sendPacket(Packet p) throws IOException {
        socket.getOutputStream().write(p.toByteArr());
    }

    protected synchronized void sendPacket(short encryptionType, Packet.DataType ty, byte[] data) throws IOException {
        byte b[] = new Packet(encryptionType, ty, data).toByteArr();

        socket.getOutputStream().write(
                b
        );
    }

    protected synchronized void sendPacket(Packet.DataType ty, byte[] data) throws IOException {
        byte b[] = new Packet((short) 0, ty, data).toByteArr();

        socket.getOutputStream().write(
                b
        );
    }

    @Override
    public void close() throws IOException {
        socket.close();
    }

    protected void handshake() {
        //handshake phase
        boolean done = false;
        
        try {
            System.out.println("\nsending login request");

            sendPacket((short) 1, Packet.DataType.LOGIN, new byte[0]);
        } catch (IOException ex) {
            Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, "End when trying to autenticate the client", ex);
        }
        
        while (!done) {

            Packet p;
            try {
                p = pb.getNext();
            } catch (IOException ex) {
                Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, "End when trying to read the response from the client", ex);
                break;
            }

            switch (p.getDataCode()) {
                case ID:

                    user.assignNewId();

                    try {

                        System.out.println("sending new id");
                        sendPacket(Packet.DataType.ID, Utility.longToBytes(user.getId()));

                        if (user.getPassword() == null) {

                            System.out.println("sending request of password");
                            sendPacket((short) 1, Packet.DataType.PASSWORD, null);
                        }
                        if (user.getSpecifics() == null) {

                            System.out.println("sending request of specifics");
                            sendPacket((short) 1, Packet.DataType.SPECIFICS, null);
                        }
                    } catch (IOException ex) {
                        Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, "End when the client was trying to sign up", ex);
                    }

                    break;

                case PASSWORD:
                    String pwd = new String(p.getData());

                    user.setPassword(pwd);

                    try {
                        System.out.println("\nsending login request");

                        sendPacket((short) 1, Packet.DataType.LOGIN, new byte[0]);
                    } catch (IOException ex) {
                        Logger.getLogger(Connection.class.getName()).log(Level.SEVERE, "End when trying to autenticate the client", ex);
                    }

                    break;

                case SPECIFICS:

                    String spec = new String(p.getData());

                    user.setSpecifics(spec);

                    break;

                case LOGIN:

                    String credentials = new String(p.getData());
                    StringTokenizer st = new StringTokenizer(credentials);

//                    user.setId(Long.valueOf(st.nextToken()));
//                    user.setPassword(st.nextToken());
                    System.out.println("login done");
                    //verify credentials

                    done = true;

                    break;
            }
        }
        System.out.println("end of handshake phase");
    }
}
